// exception.cc 
//	Entry point into the Nachos kernel from user programs.
//	There are two kinds of things that can cause control to
//	transfer back to here from user code:
//
//	syscall -- The user code explicitly requests to call a procedure
//	in the Nachos kernel.  Right now, the only function we support is
//	"Halt".
//
//	exceptions -- The user code does something that the CPU can't handle.
//	For instance, accessing memory that doesn't exist, arithmetic errors,
//	etc.  
//
//	Interrupts (which can also cause control to transfer from user
//	code into the Nachos kernel) are handled elsewhere.
//
// For now, this only handles the Halt() system call.
// Everything else core dumps.
//
// Copyright (c) 1992-1993 The Regents of the University of California.
// All rights reserved.  See copyright.h for copyright notice and limitation 
// of liability and disclaimer of warranty provisions.

#include "copyright.h"
#include "system.h"
#include "syscall.h"
#include <stdio.h>
#include <iostream>

using namespace std;

int copyin(unsigned int vaddr, int len, char *buf) {
    // Copy len bytes from the current thread's virtual address vaddr.
    // Return the number of bytes so read, or -1 if an error occors.
    // Errors can generally mean a bad virtual address was passed in.
    bool result;
    int n=0;			// The number of bytes copied in
    int *paddr = new int;


	int* tt = new int(1);
	char* t;
	t = (char *)tt;

	/*printf("It is a TEST \n");
	for(int i=0;i<4;i++)
		printf("The byte is : [%02x] , corresponding to '%c' \n", t[i], t[i]);
	*/

	while ( n >= 0 && n < len) 
	{
      result = machine->ReadMem( vaddr, 1, paddr );					//OceanMaster: Notion!!!
      while(!result) // FALL 09 CHANGES
	  {
   			result = machine->ReadMem( vaddr, 1, paddr ); // FALL 09 CHANGES: TO HANDLE PAGE FAULT IN THE ReadMem SYS CALL
	  }	
      
      buf[n++] = *paddr;
	
	  //printf("The byte just copied is : [%02x] , corresponding to '%c' \n", buf[n-1], buf[n-1]);

      if ( !result ) {
		//translation failed
		return -1;
      }

      vaddr++;
    }

    delete paddr;
    return len;
}

//-----------------Project 2---------------------
//Added by OceanMaster
//to convert BIG_ENDIN to SMALL_ENDIN
//or OTHERWISE
//used by Write_Format_Syscall
//-----------------------------------------------
#include <stdlib.h>

#define R_MAX 2147483647

int
Convert(int word)
{
	unsigned int in = (unsigned int) word;
	unsigned int out;

	out  = (in>>24) & 0x000000ff;
	out |= (in>>8 ) & 0x0000ff00;
	out |= (in<<8 ) & 0x00ff0000;
	out |= (in<<24) & 0xff000000;

	return (int) out;
}

//check Boundary of Virtual Address
bool
CheckBoundary(unsigned int Vaddr, int len, bool isCode)
{
	if(isCode)
	{
		unsigned int codeSize = currentThread -> space -> GetCodeSize();
	
		if(Vaddr >= codeSize)						//Code Vaddr should be inside code segment
		{
			printf("ERROR: Virtual Address Over Code Segment \n");
			return false;
		}

		if(len <0)									//len should be over zero
		{
			printf("ERROR: Buffer length should't be negative \n");
			return false;
		}

		if(Vaddr + len >= codeSize)					//copy end should be inside code segment
		{	
			printf("ERROR: Copy Target Virtual Address Over Code Segment \n");
			return false;
		}

		if(Vaddr + len < Vaddr)						//In case len is too BIG that overflows int
		{
			printf("ERROR: Copy length are TOO BIG, Boundary Overflow \n");
			return false;
		}
	}
	else
	{
		unsigned int numPages = currentThread -> space -> GetNumPages();
	
		if(Vaddr >= numPages * PageSize)			//Vaddr should be inside virtual space
		{
			printf("ERROR: Virtual Address Over Bounds \n");
			return false;
		}

		if(len <0)									//len should be over zero
		{
			printf("ERROR: Buffer length should't be negative \n");
			return false;
		}

		if(Vaddr + len >= numPages * PageSize)		//copy end should be inside virtual space
		{	
			printf("ERROR: Copy Target Virtual Address Over Bounds \n");
			return false;
		}

		if(Vaddr + len < Vaddr)						//In case len is too BIG that overflows int
		{
			printf("ERROR: Copy length are TOO BIG, Boundary Overflow \n");
			return false;
		}
	}

	return true;
}

//-----------------------------------------------
//					  end					   */
//-----------------------------------------------

int copyout(unsigned int vaddr, int len, char *buf) {
    // Copy len bytes to the current thread's virtual address vaddr.
    // Return the number of bytes so written, or -1 if an error
    // occors.  Errors can generally mean a bad virtual address was
    // passed in.
    bool result;
    int n=0;			// The number of bytes copied in

    while ( n >= 0 && n < len) {
      // Note that we check every byte's address
      result = machine->WriteMem( vaddr, 1, (int)(buf[n++]) );

      if ( !result ) {
	//translation failed
	return -1;
      }

      vaddr++;
    }

    return n;
}

void Create_Syscall(unsigned int vaddr, int len) {
    // Create the file with the name in the user buffer pointed to by
    // vaddr.  The file name is at most MAXFILENAME chars long.  No
    // way to return errors, though...
    char *buf = new char[len+1];	// Kernel buffer to put the name in

    if (!buf) return;

    if( copyin(vaddr,len,buf) == -1 ) {
	printf("%s","Bad pointer passed to Create\n");
	delete buf;
	return;
    }

    buf[len]='\0';

    fileSystem->Create(buf,0);
    delete[] buf;
    return;
}

int Open_Syscall(unsigned int vaddr, int len) {
    // Open the file with the name in the user buffer pointed to by
    // vaddr.  The file name is at most MAXFILENAME chars long.  If
    // the file is opened successfully, it is put in the address
    // space's file table and an id returned that can find the file
    // later.  If there are any errors, -1 is returned.
    char *buf = new char[len+1];	// Kernel buffer to put the name in
    OpenFile *f;			// The new open file
    int id;				// The openfile id

    if (!buf) {
	printf("%s","Can't allocate kernel buffer in Open\n");	//Commented by OceanMaster: so that the char * won't take user prog's stack, but core stack instead
	return -1;
    }

    if( copyin(vaddr,len,buf) == -1 ) {
	printf("%s","Bad pointer passed to Open\n");
	delete[] buf;
	return -1;
    }

    buf[len]='\0';

    f = fileSystem->Open(buf);
    delete[] buf;

    if ( f ) {
	if ((id = currentThread->space->fileTable.Put(f)) == -1 )
	    delete f;
	return id;
    }
    else
	return -1;
}

void Write_Syscall(unsigned int vaddr, int len, int id) {
    // Write the buffer to the given disk file.  If ConsoleOutput is
    // the fileID, data goes to the synchronized console instead.  If
    // a Write arrives for the synchronized Console, and no such
    // console exists, create one. For disk files, the file is looked
    // up in the current address space's open file table and used as
    // the target of the write.
    
    char *buf;		// Kernel buffer for output
    OpenFile *f;	// Open file for output

    if ( id == ConsoleInput) return;
    
    if ( !(buf = new char[len]) ) {
	printf("%s","Error allocating kernel buffer for write!\n");
	return;
    } else {
        if ( copyin(vaddr,len,buf) == -1 ) {
	    printf("%s","Bad pointer passed to to write: data not written\n");
	    delete[] buf;
	    return;
	}
    }

    if ( id == ConsoleOutput) {
      for (int ii=0; ii<len; ii++) {
	printf("%c",buf[ii]);
      }

    } else {
	if ( (f = (OpenFile *) currentThread->space->fileTable.Get(id)) ) {
	    f->Write(buf, len);
	} else {
	    printf("%s","Bad OpenFileId passed to Write\n");
	    len = -1;
	}
    }

    delete[] buf;
}

int Read_Syscall(unsigned int vaddr, int len, int id) {
    // Write the buffer to the given disk file.  If ConsoleOutput is
    // the fileID, data goes to the synchronized console instead.  If
    // a Write arrives for the synchronized Console, and no such
    // console exists, create one.    We reuse len as the number of bytes
    // read, which is an unnessecary savings of space.
    char *buf;		// Kernel buffer for input
    OpenFile *f;	// Open file for output

    if ( id == ConsoleOutput) return -1;
    
    if ( !(buf = new char[len]) ) {
	printf("%s","Error allocating kernel buffer in Read\n");
	return -1;
    }

    if ( id == ConsoleInput) {
      //Reading from the keyboard
      scanf("%s", buf);

      if ( copyout(vaddr, len, buf) == -1 ) {
	printf("%s","Bad pointer passed to Read: data not copied\n");
      }
    } else {
	if ( (f = (OpenFile *) currentThread->space->fileTable.Get(id)) ) {
	    len = f->Read(buf, len);
	    if ( len > 0 ) {
	        //Read something from the file. Put into user's address space
  	        if ( copyout(vaddr, len, buf) == -1 ) {
		    printf("%s","Bad pointer passed to Read: data not copied\n");
		}
	    }
	} else {
	    printf("%s","Bad OpenFileId passed to Read\n");
	    len = -1;
	}
    }

    delete[] buf;
    return len;
}

void Close_Syscall(int fd) {
    // Close the file associated with id fd.  No error reporting.
    OpenFile *f = (OpenFile *) currentThread->space->fileTable.Remove(fd);

    if ( f ) {
      delete f;
    } else {
      printf("%s","Tried to close an unopen file\n");
    }
}

//-------------------------------------------------------
// Added as Project2
// New Sys Calls and needed sub functions
// by OceanMaster
//-------------------------------------------------------

//-----------------------
//     Thread Related
//-----------------------

void
Yield_Syscall()
{
	DEBUG('2',"Thread '%s' yield \n", currentThread->getName());
	currentThread->Yield();
}

void
Exit_Syscall(int status)
{
	if(status < 0)													//check status
	{
		printf("ERROR: Invalid Exit Status : %d , Exit Failed \n", status);
		return;
	}
	
	printf("User Program Calling Exit(%d), processId=%d, threadId=%d \n",status, currentThread->processId, currentThread->threadId);

	DEBUG('2',"Thread '%s' Exit \n", currentThread->getName());
	
	KernelProcess * process = GetProcess(currentThread -> processId);

	process -> deleteCurrentThread();								//Update process table and check machine status
	
	currentThread -> Finish();										//If it isn't last thread in last process, finsh self
																	//Otherwise, it should had halted system before this command
}

//!!!!!!!!!!!!!!!!!!!!!Project 2!!!!!!!!!!!!!!!!!!!!!!!!!!
//OceanMaster:
//	We used CheckBoundary() and ReadMem builtin Check
//	To make sure Buff and Memory Security
//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!


//Description: 
//	This syscall will start a new thread and let that thread do the forked function.
//This is a syscall exposed to user program, it won't support another argument
//Assumption:
//	1)currentThread holds the same process as forked thread will be in
//	2)parent process's space has been set up
//	3)We have to Assign ProcessId to thread before we call FORK
//	4)We have to Assign threadId to thread before we call FORK
void
Fork_Syscall(unsigned int Vaddr)
{
	if(!CheckBoundary(Vaddr,4,true))
		return;

	//Step1: Create new Thread
	char * name = new char[13];
	sprintf(name,"Thread_%05d",ThreadIndex++);
	Thread * thread = new Thread(name);			
	delete[] name;	//We Rewrote thread constructor to store name seperately, so we can delete it here.
	
	DEBUG('2',"Thread '%s' Forked another thread '%s' , address : 0x%0x \n", currentThread->getName(),name, Vaddr);
	
	//Step2: Assign Parent Process's id to forked thread
			//AddrSpace * space = currentThread -> space;
			//thread -> space = space;				
	thread -> processId = currentThread -> processId;
	//Step3: Assign Thread Id
	thread -> threadId = GetProcess(currentThread -> processId) -> AssignThreadId();
	//Important: Have to Explicitly assign thread id before current thread return

	//Step4: Call Fork, Run Load function, it will set other information in process table and forked thread
	thread -> Fork(LoadUserFunction,Vaddr);
}



//Assumption:
//	1)Assign processId to thread
//	2)Assign ThreadId to thread
//	3)Make sure space is created
int
Exec_Syscall(unsigned int vaddr, int length)
{
	if(!CheckBoundary(vaddr,length,false))
		return -1;

	//Step1: Create new Thread
	char * name = new char[13];
	sprintf(name,"Thread_%05d",ThreadIndex++);
	Thread * thread = new Thread(name);
	delete[] name;	//We Rewrote thread constructor to store name seperately, so we can delete it here.
	
	//Step2: Open Executable File for reading
	
	char * buf = new char[length+1];				// Kernel buffer to put the name in

    if (!buf) 
		return -1;
    if( copyin(vaddr,length,buf) == -1 ) 
	{
		printf("%s","Bad pointer passed to Exec\n");
		delete buf;
		return -1;
    }
    buf[length]='\0';
	
	DEBUG('2',"Thread '%s' Execute another thread '%s' to run user program '%s' \n", currentThread->getName(), thread->getName(), buf);
	
	OpenFile * executable = fileSystem->Open(buf);

	if(executable == NULL)
	{
		printf("FATAL ERROR: File name passed in can't be opened to run, EXEC quit \n");
		return -1;
	}

	//-------------------------
	//	Modified in Project3
	//-------------------------

	//Step3: Assign ProcessId and ThreadId to thread
	int processId = AddProcess();
	thread -> processId = processId;
	KernelProcess * process = GetProcess(processId);
	thread -> threadId = process -> AssignThreadId();	//Explicitly assign thread Id

	//Step4: Fork LoadUserFunction with Vaddr:0 (Program entry), start user program
	thread -> Fork(LoadUserProgram, (int)executable);

	//Step5: recycle resource, and return value	

	//delete executable;			// Modified in Project3, already deleted in LoadUserProgram
	
	delete[] buf;
	
	return processId;
}


void Write_Format_Syscall(unsigned int vaddr, int len, int argVaddr, int argnum) 
{
	if(!CheckBoundary(vaddr,len,false))
		return;
	
	if(!CheckBoundary(argVaddr,4*argnum,false))
		return;

	// Write the buffer to screen.
	// Format like printf

    char * buf;		// Kernel buffer for format string
	int * args;		// Kernel buffer for args

    if ( !(buf = new char[len+1]) )						//allocate buf
	{
		printf("%s","Error allocating kernel buffer for write format!\n");
		return;
    } 
	else 
	{
        if ( copyin(vaddr,len,buf) == -1 )				//copy Format form user space to buf
		{
			printf("%s","Bad pointer passed to to write format: data not written\n");
			delete[] buf;
			return;
		}
    }

	buf[len] = '\0';			//!!! Bug Fixed!!!

	
	if(argnum > 0)
	{
		if ( !(args = new int[argnum]) )					//allocate args
		{
			printf("%s","Error allocating kernel buffer for write format!\n");
			delete[] buf;
			return;
		} else 
		{
			if ( copyin(argVaddr,argnum * sizeof(int) / sizeof(char),(char *)args) == -1 ) //copy Args from user space to args
			{
				printf("%s","Bad pointer passed to to write format: data not written\n");
				delete[] buf;
				delete[] args;
				return;
			}
		}
		//Convert from coff (small_endin) to ef (big_endin) int
		for(int i=0;i<argnum;i++)
			args[i] = Convert(args[i]);
	}


	//Write Format Main Function:
	switch(argnum)
	{
		case 0:
			printf(buf);
			break;

		case 1:
			printf(buf,args[0]);
			break;
		
		case 2:
			printf(buf,args[0],args[1]);
			break;

		case 3:
			printf(buf,args[0],args[1],args[2]);
			break;
		
		case 4:
			printf(buf,args[0],args[1],args[2],args[3]);
			break;

		case 5:
			printf(buf,args[0],args[1],args[2],args[3],args[4]);
			break;

		case 6:
			printf(buf,args[0],args[1],args[2],args[3],args[4],args[5]);
			break;

		default:
			printf("ERROR: WriteFormat arg num too many, write format fails \n");
	
	}
    
	delete[] buf;
	if(argnum>0)					//Bug fixed !!
		delete[] args;
}

int 
Random_Syscall(int limit)
{
	int result = (int) (limit * (double) rand() / ((double) R_MAX + 1.0));
	return result;
}

//-----------------------
//     Lock Related
//-----------------------

int
Create_Lock_Syscall(unsigned int vaddr, int length)
{

	if(!CheckBoundary(vaddr,length,false))
		return -1;

    // Create the Lock with name
	// name is in the user buffer pointed to by vaddr.
	int index = -1;
    char * buf = new char[length+1];				// Kernel buffer to put the name in

    if (!buf) 
		return index;

    if( copyin(vaddr,length,buf) == -1 ) 
	{
		printf("%s","Bad pointer passed to Create\n");
		delete buf;
		return index;
    }

    buf[length]='\0';

	Lock * lock = new Lock(buf);
	
	index = RegisterLock(lock);

	DEBUG('2',"Thread '%s' Created Lock [%d] with name '%s' \n", currentThread->getName(), index, buf);

    //delete[] buf;									//!!! We don't delete buf because Lock need it to store name

    return index;
}

void
Destroy_Lock_Syscall(int index)
{
 	DEBUG('2',"Thread '%s' Delete Lock [%d] \n", currentThread->getName(), index);
	DeleteLock(index);
}

void
Acquire_Lock_Syscall(int index)
{
	DEBUG('2',"Thread '%s' Acquire Lock [%d] \n", currentThread->getName(), index);
	AcquireLock(index);
}

void
Release_Lock_Syscall(int index)
{
	DEBUG('2',"Thread '%s' Release Lock [%d] \n", currentThread->getName(), index);
	ReleaseLock(index);
}

//-----------------------
//   condition Related
//-----------------------

int
Create_CV_Syscall(unsigned int vaddr, int length)
{
	if(!CheckBoundary(vaddr,length,false))
		return -1;

    // Create the Lock with name
	// name is in the user buffer pointed to by vaddr.
	int index = -1;
    char * buf = new char[length+1];				// Kernel buffer to put the name in

    if (!buf) 
		return index;

    if( copyin(vaddr,length,buf) == -1 ) 
	{
		printf("%s","Bad pointer passed to Create\n");
		delete buf;
		return index;
    }

    buf[length]='\0';

	Condition * cond = new Condition(buf);
	
	index = RegisterCondition(cond);

	DEBUG('2',"Thread '%s' Created Condition [%d] with name '%s' \n", currentThread->getName(), index, buf);

	//delete[] buf;									//!!! We don't delete buf because Lock need it to store name

	return index;
}

void
Destroy_CV_Syscall(int index)
{
	DEBUG('2',"Thread '%s' Destroy Condition [%d] \n", currentThread->getName(), index);
 	DeleteCondition(index);
}

void
Wait_CV_Syscall(int cond_index, int lock_index)
{
	DEBUG('2',"Thread '%s' Wait Condition [%d] with Lock [%d] \n", currentThread->getName(), cond_index, lock_index);
	WaitCondition(cond_index, lock_index);
}

void
Signal_CV_Syscall(int cond_index, int lock_index)
{
	DEBUG('2',"Thread '%s' Signal Condition [%d] with Lock [%d] \n", currentThread->getName(), cond_index, lock_index);
	SignalCondition(cond_index, lock_index);
}

void
Broadcast_CV_Syscall(int cond_index, int lock_index)
{
	DEBUG('2',"Thread '%s' Broadcast Condition [%d] with Lock [%d] \n", currentThread->getName(), cond_index, lock_index);
	BroadcastCondition(cond_index, lock_index);
}

/*
 * For distributed locks and CVs
 *
 */

#ifdef NETWORK

//------------------Project 4---------------------
//Utility
int RandomServerTarget()				//Randomly pick a server machine to send msg
{
	int sid;
	if(serverNum == 1)
		sid = 0;
	else
		sid = Random_Syscall(serverNum);
	DEBUG('7',"Send message to server #%d\n",sid);
	return sid;
}

int MyMailBox()
{
	int mailBox = currentThread -> getMailBox();
	DEBUG('7',"My mail box is #%d\n",mailBox);
	return mailBox;
}


int
Remote_Create_Lock_Syscall(unsigned int vaddr, int length)
{
	PacketHeader outPktHdr,inPktHdr;
	MailHeader outMailHdr,inMailHdr;
	int replyLength=0;
	if(!CheckBoundary(vaddr,length,false))
		return -1;

    // Create the Lock with name
	// name is in the user buffer pointed to by vaddr.
	int index = -1;
	if (length>35)
	{
		printf("ERROR : The length of the lock name is too long. The length is %d\n",length);
		return index;
	}
	if (length<0)
	{
		printf("ERROR : The length of the lock name should not be negative!\n");
		return index;
	}
    char * buf = new char[length+1];				// Kernel buffer to put the name in

    if (!buf) 
	return index;

    if( copyin(vaddr,length,buf) == -1 ) 
    {
		printf("%s","ERROR : Bad pointer passed to Create\n");
		delete buf;
		return index;
    }
	buf[length]='\0';

	char buffer[MaxMailSize];

    char* data=new char[40];
	data[0]='0';
	data[1]='0';
    sprintf(data+2,"%02d%s",length,buf);
	
	outPktHdr.to=RandomServerTarget();
	outMailHdr.to=0;
	outMailHdr.from=MyMailBox();
	outMailHdr.length=strlen(data)+1;
	DEBUG('N', "Try to send create lock request to server.\n");
    //send the request message to the server
    int success= postOffice->Send(outPktHdr,outMailHdr,data);
	DEBUG('6',"Machine%dBox%d trying to create Lock %s\n",netname, outMailHdr.from,buf );

	if (!success)
	{
		printf("ERROR : The postOffice Send failed. You must not have the other Nachos running. Terminating Nachos.\n");
		interrupt->Halt();
	}
	postOffice->Receive(MyMailBox(),&inPktHdr,&inMailHdr,buffer);
	DEBUG('N', "Get the reply message from server.\n");
	if (buffer[0]=='0')
	{
		char* tempLength=new char[3];
		tempLength[0]=buffer[1];
		tempLength[1]=buffer[2];
		tempLength[2]='\0';
		replyLength=atoi(tempLength);
		printf("ERROR REPLY : %s\n",buffer+3);
	}
	else if (buffer[0]=='1')
	{
		index=atoi(buffer+1);
		DEBUG('6',"Machine%dBox%d create the Lock successfully. The Lock id is %s\n",netname, outMailHdr.from,buffer+1);

	}
	
    return index;
}

void
Remote_Destroy_Lock_Syscall(int index)
{
	PacketHeader outPktHdr,inPktHdr;
	MailHeader outMailHdr,inMailHdr;
 	DEBUG('2',"Thread '%s' Delete Lock [%d] \n", currentThread->getName(), index);
	if (index>9999)
	{
		printf("ERROR : The lock index is too big!\n");
	}
	if (index<0)
	{
		printf("ERROR : The lock index should not be negative!\n");
	}
	char buffer[MaxMailSize];
	char* data=new char[40];
	data[0]='0';
	data[1]='3';
	sprintf(data+2,"%04d",index);
	data[6]='\0';
	outPktHdr.to=RandomServerTarget();
	outMailHdr.to=0;
	outMailHdr.from=MyMailBox();
	outMailHdr.length=strlen(data)+1;
    /*send the request message to the server*/
	DEBUG('N', "Try to send Destroy lock request to server.\n");
    int success=postOffice->Send(outPktHdr,outMailHdr,data);
	DEBUG('6',"Machine%dBox%d trying to destroy Lock #%d\n",netname, outMailHdr.from,index );
	if (!success)
	{
		printf("ERROR : The postOffice Send failed. You must not have the other Nachos running. Terminating Nachos.\n");
		interrupt->Halt();
	}

	postOffice->Receive(MyMailBox(),&inPktHdr,&inMailHdr,buffer);
	DEBUG('6', "Get the reply message from server.\n");
	if (buffer[0]=='0')
	{
		
		char* tempLength=new char[3];
		tempLength[0]=buffer[1];
		tempLength[1]=buffer[2];
		tempLength[2]='\0';
		int replyLength=atoi(tempLength);
		printf("ERROR REPLY : %s\n",buffer+3);
	}
	if (buffer[0]=='1')
	{
		DEBUG('6',"Destroy the lock successfully!\n");
	}
	//else if (buffer[])
	//DeleteLock(index);
}

void
Remote_Acquire_Lock_Syscall(int index)
{
	PacketHeader outPktHdr,inPktHdr;
	MailHeader outMailHdr,inMailHdr;
	//AcquireLock(index);
	if (index>9999)
	{
		printf("ERROR : The lock index is too big!\n");
	}
	if (index<0)
	{
		printf("ERROR : The lock index should not be negative!\n");
	}
	char buffer[MaxMailSize];
	char* data=new char[40];
	data[0]='0';
	data[1]='1';
	sprintf(data+2,"%04d",index);
	data[6]='\0';
	outPktHdr.to=RandomServerTarget();
	outMailHdr.to=0;
	outMailHdr.from=MyMailBox();
	outMailHdr.length=strlen(data)+1;
    /*send the request message to the server*/
	DEBUG('6', "Try to send Acquire lock request to server.\n");
	int success=postOffice->Send(outPktHdr,outMailHdr,data);
	DEBUG('6',"Machine%dBox%d trying to Acquire Lock #%d\n",netname, outMailHdr.from,index );
	if (!success)
	{
		printf("ERROR : The postOffice Send failed. You must not have the other Nachos running. Terminating Nachos.\n");
		interrupt->Halt();
	}
	postOffice->Receive(MyMailBox(),&inPktHdr,&inMailHdr,buffer);
	DEBUG('6', "Get the reply message from server.\n");
	if (buffer[0]=='0')
	{
		printf("ERROR REPLY : %s\n",buffer+3);
	}
	else if (buffer[0]=='1')
	{
		DEBUG('6',"Acquire the lock successfully!\n");
	}
}

void
Remote_Release_Lock_Syscall(int index)
{
	PacketHeader outPktHdr,inPktHdr;
	MailHeader outMailHdr,inMailHdr;
	//	ReleaseLock(index);
	if (index>9999)
	{
		printf("ERROR : The lock index is too big!\n");
	}
	if (index<0)
	{
		printf("ERROR : The lock index should not be negative!\n");
	}
	char buffer[MaxMailSize];
	char* data=new char[40];
	data[0]='0';
	data[1]='2';
	sprintf(data+2,"%04d",index);
	data[6]='\0';
	outPktHdr.to=RandomServerTarget();
	outMailHdr.to=0;
	outMailHdr.from=MyMailBox();
	outMailHdr.length=strlen(data)+1;
    /*send the request message to the server*/
    DEBUG('6', "Try to send Release lock request to server\n");
	int success=postOffice->Send(outPktHdr,outMailHdr,data);
	DEBUG('6',"Machine%dBox%d trying to release Lock #%d\n",netname, outMailHdr.from,index );
	if (!success)
	{
		printf("ERROR : The postOffice Send failed. You must not have the other Nachos running. Terminating Nachos.\n");
		interrupt->Halt();
	}
	postOffice->Receive(MyMailBox(),&inPktHdr,&inMailHdr,buffer);
	DEBUG('N', "Get the reply message from server.\n");
	if (buffer[0]=='0')
	{
		printf("ERROR REPLY : %s\n",buffer+3);
	}
	else if (buffer[0]=='1')
	{
		DEBUG('6',"Release the lock successfully!\n");
	}

}

//-----------------------
//   condition Related
//-----------------------

int
Remote_Create_CV_Syscall(unsigned int vaddr, int length)
{
	PacketHeader outPktHdr,inPktHdr;
	MailHeader outMailHdr,inMailHdr;
	int index=-1;
	if (length>35)
	{
		printf("ERROR : The length of the CV name is too long. The length is %d\n",length);
		return index;
	}
	if (length<0)
	{
		printf("ERROR : The length of the CV name should not be negative!\n");
		return index;
	}

	if(!CheckBoundary(vaddr,length,false))
	return -1;

    // Create the Lock with name
	// name is in the user buffer pointed to by vaddr.
    	char * buf = new char[length+1];				// Kernel buffer to put the name in

 	if (!buf) 
	return index;

    if( copyin(vaddr,length,buf) == -1 ) 
	{
		printf("%s","ERROR : Bad pointer passed to Create\n");
		delete buf;
		return index;
    }

    buf[length]='\0';
	char buffer[MaxMailSize];

    char* data=new char[40];
	data[0]='0';
	data[1]='4';
    sprintf(data+2,"%02d%s",length,buf);
	outPktHdr.to=RandomServerTarget();
	outMailHdr.to=0;
	outMailHdr.from=MyMailBox();
	outMailHdr.length=strlen(data)+1;
    /*send the request message to the server*/
    DEBUG('6', "Try to send Create condition request to server.\n");
	int success=postOffice->Send(outPktHdr,outMailHdr,data);
	DEBUG('6',"Machine%dBox%d trying to create Condition %s\n",netname, outMailHdr.from,buf );
	if (!success)
	{
		printf("ERROR : The postOffice Send failed. You must not have the other Nachos running. Terminating Nachos.\n");
		interrupt->Halt();
	}
	postOffice->Receive(MyMailBox(),&inPktHdr,&inMailHdr,buffer);
	DEBUG('6', "Get the reply message from server.\n");


	//delete[] buf;									//!!! We don't delete buf because Lock need it to store name
	if (buffer[0]=='0')
	{
		char* tempLength=new char[3];
		tempLength[0]=buffer[1];
		tempLength[1]=buffer[2];
		tempLength[2]='\0';
		int replyLength=atoi(tempLength);
		printf("ERROR REPLY : %s\n",buffer+3);

	}
	else if (buffer[0]=='1')
	{
		index=atoi(buffer+1);
		DEBUG('6',"Create the CV successfully. The CV id is %s\n",buffer+1);

	}

	return index;
}

void
Remote_Destroy_CV_Syscall(int index)
{
	PacketHeader outPktHdr,inPktHdr;
	MailHeader outMailHdr,inMailHdr;
	if (index>9999)
	{
		printf("ERROR : The CV index is too big!\n");
	}
	if (index<0)
	{
		printf("ERROR : The CV index should not be negative!\n");
	}
	char buffer[MaxMailSize];
	char* data=new char[40];
	data[0]='0';
	data[1]='8';
	sprintf(data+2,"%04d",index);
	data[6]='\0';
	outPktHdr.to=RandomServerTarget();
	outMailHdr.to=0;
	outMailHdr.from=MyMailBox();
	outMailHdr.length=strlen(data)+1;
    /*send the request message to the server*/
   	DEBUG('6'," Try to send Destroy Condition request to server.\n");
	int success=postOffice->Send(outPktHdr,outMailHdr,data);
	DEBUG('6',"Machine%dBox%d trying to destroy Condition #%d\n",netname, outMailHdr.from,index );
	
	if (!success)
	{
		printf("ERROR : The postOffice Send failed. You must not have the other Nachos running. Terminating Nachos.\n");
		interrupt->Halt();
	}
	postOffice->Receive(MyMailBox(),&inPktHdr,&inMailHdr,buffer);
	DEBUG('6', "Get the reply message from server.\n");
	if (buffer[0]=='0')
	{
		printf("ERROR REPLY : %s\n",buffer+3);
	}
	else if (buffer[0]=='1')
	{
		DEBUG('6',"Destroy the CV successfully!\n");
	}

	/*
	 * analyze the reply message.
	 */


 	//DeleteCondition(index);
}

void
Remote_Wait_CV_Syscall(int cond_index, int lock_index)
{
	PacketHeader outPktHdr,inPktHdr;
	MailHeader outMailHdr,inMailHdr;
	if (cond_index>9999)
	{
		printf("ERROR : The CV index is too big!\n");
		return;
	}
	else if (cond_index<0)
	{
		printf("ERROR : The CV index should not be negative!\n");
		return;
	}
	if (lock_index>9999)
	{
		printf("ERROR : The lock index is too big!\n");
		return;
	}
	else if (lock_index<0)
	{
		printf("ERROR : The lock index should not be negative!\n");
		return;
	}
	char buffer[MaxMailSize];
	char* data=new char[40];
	data[0]='0';
	data[1]='5';
	sprintf(data+2,"%04d%04d",lock_index,cond_index);
	data[10]='\0';
	outPktHdr.to=RandomServerTarget();
	outMailHdr.to=0;
	outMailHdr.from=MyMailBox();
	outMailHdr.length=strlen(data)+1;
    /*send the request message to the server*/
    DEBUG('6', "Try to send Wait condition request to server");
	int success= postOffice->Send(outPktHdr,outMailHdr,data);
	DEBUG('6',"Machine%dBox%d trying to wait Condition #%d with lock #%d\n",netname, outMailHdr.from,cond_index, lock_index );
	
	if (!success)
	{
		printf("ERROR : The postOffice Send failed. You must not have the other Nachos running. Terminating Nachos.\n");
		interrupt->Halt();
	}
	postOffice->Receive(MyMailBox(),&inPktHdr,&inMailHdr,buffer);
	DEBUG('6', "Get the reply message from server.\n");
	if (buffer[0]=='0')
	{
		printf("ERROR REPLY : %s\n",buffer+3);
	}
	else if (buffer[0]=='1')
	{
		DEBUG('6',"This client has been waken up!\n");
		//postOffice->Receive(0,&inPktHdr,&inMailHdr,buffer);

		//printf("successfully wait!\n");
	}
	
	//WaitCondition(cond_index, lock_index);
}

void
Remote_Signal_CV_Syscall(int cond_index, int lock_index)
{
	PacketHeader outPktHdr,inPktHdr;
	MailHeader outMailHdr,inMailHdr;

	if (cond_index>9999)
	{
		printf("ERROR : The CV index is too big!\n");
		return;
	}
	else if (cond_index<0)
	{
		printf("ERROR : The CV index should not be negative!\n");
		return;
	}
	if (lock_index>9999)
	{
		printf("ERROR : The lock index is too big!\n");
		return;
	}
	else if (lock_index<0)
	{
		printf("ERROR : The lock index should not be negative!\n");
		return;
	}

	char buffer[MaxMailSize];
	char* data=new char[40];
	data[0]='0';
	data[1]='6';
	sprintf(data+2,"%04d%04d",lock_index,cond_index);
	data[10]='\0';
	outPktHdr.to=RandomServerTarget();
	outMailHdr.to=0;
	outMailHdr.from=MyMailBox();
	outMailHdr.length=strlen(data)+1;
   /*send the request message to the server*/;
   	DEBUG('6',"Try to send Signal condition request to server.\n");
	int success=postOffice->Send(outPktHdr,outMailHdr,data);
	DEBUG('6',"Machine%dBox%d trying to signal Condition #%d with lock #%d\n",netname, outMailHdr.from,cond_index, lock_index );
	
	if (!success)
	{
		printf("ERROR : The postOffice Send faild. You must not have the other Nachos running. Terminating Nachos.\n");
		interrupt->Halt();
	}
	DEBUG('6', "Get the reply message from server.\n");
	postOffice->Receive(MyMailBox(),&inPktHdr,&inMailHdr,buffer);
	if (buffer[0]=='0')
	{
		printf("ERROR REPLY : %s\n",buffer+3);
	}
	else if (buffer[0]=='1')
	{
		DEBUG('6',"Signal the CV successfully!\n");
	}
	return;
	//SignalCondition(cond_index, lock_index);
}

void
Remote_Broadcast_CV_Syscall(int cond_index, int lock_index)
{
	PacketHeader outPktHdr,inPktHdr;
	MailHeader outMailHdr,inMailHdr;
	if (cond_index>9999)
	{
		printf("ERROR : The CV index is too big!\n");
		return;
	}
	else if (cond_index<0)
	{
		printf("ERROR : The CV index should not be negative!\n");
		return;
	}
	if (lock_index>9999)
	{
		printf("ERROR : The lock index is too big!\n");
		return;
	}
	else if (lock_index<0)
	{
		printf("ERROR : The lock index should not be negative!\n");
		return;
	}
	char buffer[MaxMailSize];
	char* data=new char[40];
	data[0]='0';
	data[1]='7';
	sprintf(data+2,"%04d%04d",lock_index,cond_index);
	data[10]='\0';
	outPktHdr.to=RandomServerTarget();
	outMailHdr.to=0;
	outMailHdr.from=MyMailBox();
	outMailHdr.length=strlen(data)+1;
    /*send the request message to the server*/
    DEBUG('6', "Try to send Broadcast condition request to server.\n");
	int success=postOffice->Send(outPktHdr,outMailHdr,data);
	DEBUG('6',"Machine%dBox%d trying to broadcast Condition #%d with lock #%d\n",netname, outMailHdr.from,cond_index, lock_index );
	
	if (!success)
	{
		printf("ERROR : The postOffice Send faild. You must not have the other Nachos running. Terminating Nachos.\n");
		interrupt->Halt();
	}
	DEBUG('6', "Get the reply message from server.\n");
	postOffice->Receive(MyMailBox(),&inPktHdr,&inMailHdr,buffer);
	if (buffer[0]=='0')
	{
		printf("ERROR REPLY : %s\n",buffer+3);
	}
	else if (buffer[0]=='1')
	{
		DEBUG('6',"Broadcast the CV successfully!\n");
	}
	//BroadcastCondition(cond_index, lock_index);
}
/* syscalls for distributed system
   Doing the jobs of creating monitor variable,set and get the value of a monitor variable*/
int Create_MV_Syscall(unsigned int vaddr,int nameLength,int arrayLength,int initValue)
{
	PacketHeader outPktHdr,inPktHdr;
	MailHeader outMailHdr,inMailHdr;

	int MVIndex=-1;

	if (nameLength>27)
	{
		printf("ERROR : The length of the monitor variable name is too long!!\n");
		return -1;
	}
	if(!CheckBoundary(vaddr,nameLength,false))
	return -1;

    // Create the MV array with name
	// name is in the user buffer pointed to by vaddr.
    char * buf = new char[nameLength+1];				// Kernel buffer to put the name in

 	if (!buf) 
	return MVIndex;

    if( copyin(vaddr,nameLength,buf) == -1 ) 
	{
		printf("%s","ERROR : Bad pointer passed to Create\n");
		delete buf;
		return MVIndex;
    }
	buf[nameLength]='\0';

	char buffer[MaxMailSize];

    char* data=new char[40];
	data[0]='0';
	data[1]='9';

	char* value= (char *)&initValue;
    
	sprintf(data+2,"%02d%04d%c%c%c%c%s",nameLength,arrayLength,'A','A','A','A',buf);
	
	data[8] = value[0];
	data[9] = value[1];
	data[10] = value[2];
	data[11] = value[3];
	

	//DEBUG('6',"initValue = %d, hex = 0x%04x \n",initValue,initValue);
	//DEBUG('6',"value[] = 0x%02x 0x%02x 0x%02x 0x%02x\n",value[0],value[1],value[2],value[3]);
	//DEBUG('6',"CreateMV Message: [%s] \n",data);


	outPktHdr.to=RandomServerTarget();
	outMailHdr.to=0;
	outMailHdr.from=MyMailBox();
	//outMailHdr.length=strlen(data)+1;
	outMailHdr.length=12+strlen(buf)+1;
	
	DEBUG('6',"try to send message to server!\n");
    //send the request message to the server
	int success=postOffice->Send(outPktHdr,outMailHdr,data);
	DEBUG('6',"Machine%dBox%d trying to create MV, arraylength=%d initValue=%d name=%s\n",netname, outMailHdr.from,arrayLength,initValue,buf );
	
	if (!success)
	{
		printf("ThROR : Office Send faild. You must not have the other Nachos running. Terminating Nachos.\n");
		interrupt->Halt();
	}
	DEBUG('6', "Get the reply message from server.\n");
	postOffice->Receive(MyMailBox(),&inPktHdr,&inMailHdr,buffer);
	if (buffer[0]=='0')
	{
		printf("ERROR REPLY : %s\n",buffer+3);
	}
	else if (buffer[0]=='1')
	{
		MVIndex=atoi(buffer+1);
		DEBUG('6',"Create MV successfully! The index of MV is %d\n",MVIndex);
	}
	return MVIndex;
}


void
Destroy_MV_Syscall(int index)
{
	PacketHeader outPktHdr,inPktHdr;
	MailHeader outMailHdr,inMailHdr;

	/*Check if the index is out of bound*/
	if (index>9999)
	{
		printf("ERROR : The MV index is too big!\n");
		return;
	}
	if (index<0)
	{
		printf("ERROR : The MV index should not be negative!\n");
		return;
	}
	char buffer[MaxMailSize];
	char* data=new char[40];

	/*Make up the message*/
	data[0]='1';
	data[1]='2';
	sprintf(data+2,"%04d",index);
	data[6]='\0';
	outPktHdr.to=RandomServerTarget();
	outMailHdr.to=0;
	outMailHdr.from=MyMailBox();
	outMailHdr.length=strlen(data)+1;
    /*send the request message to the server*/
   	DEBUG('6'," Try to send Destroy MV request to server.\n");

	/*Receive the message*/
	int success=postOffice->Send(outPktHdr,outMailHdr,data);
	DEBUG('6',"Machine%dBox%d trying to destroy MV #%d\n",netname, outMailHdr.from,index );
	
	if (!success)
	{
		printf("ERROR : The postOffice Send failed. You must not have the other Nachos running. Terminating Nachos.\n");
		interrupt->Halt();
	}
	postOffice->Receive(MyMailBox(),&inPktHdr,&inMailHdr,buffer);
	DEBUG('6', "Get the reply message from server.\n");
	if (buffer[0]=='0')
	{
		printf("ERROR REPLY : %s\n",buffer+3);
	}
	else if (buffer[0]=='1')
	{
		DEBUG('6',"Destroy the MV successfully!\n");
	}



}
/*
   Get the MV

 */
int Get_MV_Syscall(int MVIndex,int arrayIndex)
{
	int MVValue;
	PacketHeader outPktHdr,inPktHdr;
	MailHeader outMailHdr,inMailHdr;
	if (MVIndex<0)
	{
		printf("ERROR : The index of MV should not be negative!\n");
		return -1;
	}
	if (MVIndex>9999)
	{
		printf("ERROR : The index of MV is too big!!\n");
		return -1;
	}
	if (arrayIndex<0)
	{
		printf("ERROR : The index into array should not be negative!!\n");
		return -1;
	}
	if (arrayIndex>9999)
	{
		printf("ERROR : The index into array is too big!!\n");
		return -1;
	}
	char buffer[MaxMailSize];

    char* data=new char[40];
	data[0]='1';
	data[1]='0';
    sprintf(data+2,"%04d%04d",MVIndex,arrayIndex);
	data[10]='\0';
	outPktHdr.to=RandomServerTarget();
	outMailHdr.to=0;
	outMailHdr.from=MyMailBox();
	outMailHdr.length=strlen(data)+1;
	DEBUG('6',"try to send message to server!\n");
    //send the request message to the server
	int success=postOffice->Send(outPktHdr,outMailHdr,data);
	DEBUG('6',"Machine%dBox%d trying to Get MV #%d, %dth element\n",netname, outMailHdr.from,MVIndex, arrayIndex );
	
	if (!success)
	{
		printf("ERROR : The postOffice Send faild. You must not have the other Nachos running. Terminating Nachos.\n");
		interrupt->Halt();
	}
	DEBUG('6', "Get the reply message from server.\n");
	postOffice->Receive(MyMailBox(),&inPktHdr,&inMailHdr,buffer);
	if (buffer[0]=='0')
	{
		printf("ERROR REPLY : %s\n",buffer+3);
	}
	else if (buffer[0]=='1')
	{
		MVValue=atoi(buffer+1);
		DEBUG('6',"Get MV successfully! The value of is %d\n",MVValue);
	}
	return MVValue;
}


void Set_MV_Syscall(int MVIndex,int arrayIndex,int value)
{
	PacketHeader outPktHdr,inPktHdr;
	MailHeader outMailHdr,inMailHdr;
	if (MVIndex<0)
	{
		printf("ERROR : The index of MV should not be negative!\n");
		return;
	}
	if (MVIndex>9999)
	{
		printf("ERROR : The index of MV is too big!!\n");
		return;
	}
	if (arrayIndex<0)
	{
		printf("ERROR : The index into array should not be negative!!\n");
		return;
	}
	if (arrayIndex>9999)
	{
		printf("ERROR : The index into array is too big!!\n");
		return;
	}


    // Create the MV array with name
	// name is in the user buffer pointed to by vaddr.

	char buffer[MaxMailSize];

    char* data=new char[40];
	data[0]='1';
	data[1]='1';
	
	int initValue = value;
	char* svalue= (char *)&initValue;
    
	sprintf(data+2,"%04d%04d%c%c%c%c",MVIndex,arrayIndex,'A','A','A','A');
	
	data[10] = svalue[0];
	data[11] = svalue[1];
	data[12] = svalue[2];
	data[13] = svalue[3];
	
	DEBUG('6',"initValue = %d, hex = 0x%04x \n",initValue,initValue);
	DEBUG('6',"value[] = 0x%02x 0x%02x 0x%02x 0x%02x\n", svalue[0],svalue[1],svalue[2],svalue[3]);
	
	data[14]='\0';
	
	outPktHdr.to=RandomServerTarget();
	outMailHdr.to=0;
	outMailHdr.from=MyMailBox();
	outMailHdr.length=15;
	DEBUG('6',"try to send message to server!\n");
    //send the request message to the server
	int success=postOffice->Send(outPktHdr,outMailHdr,data);
	DEBUG('6',"Machine%dBox%d trying to Set MV #%d, %dth element = %d\n",netname, outMailHdr.from,MVIndex, arrayIndex, value );
	
	if (!success)
	{
		printf("ERROR : The postOffice Send faild. You must not have the other Nachos running. Terminating Nachos.\n");
		interrupt->Halt();
	}
	DEBUG('6', "Get the reply message from server.\n");
	postOffice->Receive(MyMailBox(),&inPktHdr,&inMailHdr,buffer);
	if (buffer[0]=='0')
	{
		printf("ERROR REPLY : %s\n",buffer+3);
	}
	else if (buffer[0]=='1')
	{
		MVIndex=atoi(buffer+1);
		DEBUG('6',"Set the MV value successfully!\n");
	}
}


#endif //network

/*
   Wait input syscall
 */
void Wait_Input_Syscall()
{
	printf("Press 'Enter' to continue\n");
	char input[20];
	gets(input);
}

/*
   Read input syscall
 */
int Read_Input_Syscall(unsigned int vaddr,int length)
{

    if(!CheckBoundary(vaddr,length,false))
		return -1;

    // Create the Lock with name
	// name is in the user buffer pointed to by vaddr.
	int index = -1;
    char * buf = new char[length+1];				// Kernel buffer to put the name in

    if (!buf) 
		return index;

    if( copyin(vaddr,length,buf) == -1 ) 
	{
		printf("%s","ERROR : Bad pointer passed to Create\n");
		delete buf;
		return index;
    }

    buf[length]='\0';

    printf("%s\nPlease Input:",buf);
    delete buf;

    char input[256]; 
    gets(input);
    return atoi(input);
}
//-------------------------------------------------------
// Add end
//-------------------------------------------------------


void ExceptionHandler(ExceptionType which) 
{
    int type = machine->ReadRegister(2); // Which syscall?
    int rv=0; 	// the return value from a syscall

    if ( which == SyscallException ) 
    {
	switch (type) 
	{
	    default:
		DEBUG('a', "Unknown syscall - shutting down.\n");
	    case SC_Halt:
		DEBUG('a', "Shutdown, initiated by user program.\n");
		interrupt->Halt();
		break;
	    case SC_Create:
		DEBUG('a', "Create syscall.\n");
		Create_Syscall(machine->ReadRegister(4), machine->ReadRegister(5));
		break;
	    case SC_Open:
		DEBUG('a', "Open syscall.\n");
		rv = Open_Syscall(machine->ReadRegister(4), machine->ReadRegister(5));
		break;
	    case SC_Write:
		DEBUG('a', "Write syscall.\n");
		Write_Syscall(machine->ReadRegister(4),
			      machine->ReadRegister(5),
			      machine->ReadRegister(6));
		break;
	    case SC_Read:
		DEBUG('a', "Read syscall.\n");
		rv = Read_Syscall(machine->ReadRegister(4),
			      machine->ReadRegister(5),
			      machine->ReadRegister(6));
		break;
	    case SC_Close:
		DEBUG('a', "Close syscall.\n");
		Close_Syscall(machine->ReadRegister(4));
		break;

		//--------------------------
		//   Added by OceanMaster
		//--------------------------

		// Thread related Sys Calls
		
		case SC_Yield:
		DEBUG('a', "Yield syscall.\n");
		Yield_Syscall();
		break;

		case SC_Fork:	//Clarified
		DEBUG('a', "Fork syscall.\n");
		Fork_Syscall(machine->ReadRegister(4));	//No extra argument
		break;

		case SC_Exec:
		DEBUG('a', "Exec syscall.\n");
		rv = Exec_Syscall(machine->ReadRegister(4),machine->ReadRegister(5));
		break;


		case SC_Exit:
		DEBUG('a', "Exit syscall.\n");
		Exit_Syscall(machine->ReadRegister(4));
		break;
		
		// Lock Related Sys Calls

		case SC_CreateLock:
		DEBUG('a', "Create lock syscall.\n");
		rv = Create_Lock_Syscall(machine->ReadRegister(4), machine->ReadRegister(5));
		break;

		case SC_AcquireLock:
		DEBUG('a', "Acquire lock syscall.\n");
		Acquire_Lock_Syscall(machine->ReadRegister(4));
		break;

		case SC_ReleaseLock:
		DEBUG('a', "Release lock syscall.\n");
		Release_Lock_Syscall(machine->ReadRegister(4));
		break;

		case SC_DestroyLock:
		DEBUG('a', "Destroy lock syscall.\n");
		Destroy_Lock_Syscall(machine->ReadRegister(4));
		break;


		// Condition Varible Related Sys Calls

		case SC_CreateCondition:
		DEBUG('a', "Create Condition syscall.\n");
		rv = Create_CV_Syscall(machine->ReadRegister(4), machine->ReadRegister(5));
		break;

		case SC_WaitCondition:
		DEBUG('a', "Wait Condition syscall.\n");
		Wait_CV_Syscall(machine->ReadRegister(4), machine->ReadRegister(5));
		break;

		case SC_SignalCondition:
		DEBUG('a', "Signal Condition syscall.\n");
		Signal_CV_Syscall(machine->ReadRegister(4), machine->ReadRegister(5));
		break;

		case SC_BroadcastCondition:
		DEBUG('a', "Broadcast Condition syscall.\n");
		Broadcast_CV_Syscall(machine->ReadRegister(4), machine->ReadRegister(5));
		break;

		case SC_DestroyCondition:
		DEBUG('a', "Destroy Condition syscall.\n");
		Destroy_CV_Syscall(machine->ReadRegister(4));
		break;

		case SC_WriteFormat:
		DEBUG('a', "Write Format syscall.\n");
		Write_Format_Syscall( machine->ReadRegister(4), machine->ReadRegister(5), machine->ReadRegister(6), machine->ReadRegister(7));
		break;
	
		case SC_Random:
		DEBUG('a', "Random syscall.\n");
		rv = Random_Syscall( machine->ReadRegister(4));
		break;
#ifdef NETWORK	
		/*Remote lock & condition syscalls*/
		case SC_RemoteCreateLock:
		DEBUG('a', "Create lock syscall.\n");
		rv = Remote_Create_Lock_Syscall(machine->ReadRegister(4), machine->ReadRegister(5));
		break;

		case SC_RemoteAcquireLock:
		DEBUG('a', "Acquire lock syscall.\n");
		Remote_Acquire_Lock_Syscall(machine->ReadRegister(4));
		break;

		case SC_RemoteReleaseLock:
		DEBUG('a', "Release lock syscall.\n");
		Remote_Release_Lock_Syscall(machine->ReadRegister(4));
		break;

		case SC_RemoteDestroyLock:
		DEBUG('a', "Destroy lock syscall.\n");
		Remote_Destroy_Lock_Syscall(machine->ReadRegister(4));
		break;


		// Condition Varible Related Sys Calls

		case SC_RemoteCreateCondition:
		DEBUG('a', "Create Condition syscall.\n");
		rv = Remote_Create_CV_Syscall(machine->ReadRegister(4), machine->ReadRegister(5));
		break;

		case SC_RemoteWaitCondition:
		DEBUG('a', "Wait Condition syscall.\n");						
		Remote_Wait_CV_Syscall(machine->ReadRegister(4), machine->ReadRegister(5));
		break;

		case SC_RemoteSignalCondition:
		DEBUG('a', "Signal Condition syscall.\n");
		Remote_Signal_CV_Syscall(machine->ReadRegister(4),machine->ReadRegister(5));
		break;

		case SC_RemoteBroadcastCondition:
		DEBUG('a', "Broadcast Condition syscall.\n");
		Remote_Broadcast_CV_Syscall(machine->ReadRegister(4),machine->ReadRegister(5));
		break;

		case SC_RemoteDestroyCondition:
		DEBUG('a', "Destroy Condition syscall.\n");
		Remote_Destroy_CV_Syscall(machine->ReadRegister(4));
		break;

		case SC_CreateMV:
		DEBUG('a', "Create MV syscall.\n");
		rv=Create_MV_Syscall(machine->ReadRegister(4),machine->ReadRegister(5),machine->ReadRegister(6),machine->ReadRegister(7));
		break;

		case SC_GetMV:
		DEBUG('a', "Get the value of MV syscall.\n");
		rv=Get_MV_Syscall(machine->ReadRegister(4), machine->ReadRegister(5));
		break;

		case SC_SetMV:
		DEBUG('a', "Set the value of MV syscall.\n");
		Set_MV_Syscall(machine->ReadRegister(4),machine->ReadRegister(5),machine->ReadRegister(6));
		break;

		case SC_DestroyMV:
		DEBUG('a',"Destroy the MV");
		Destroy_MV_Syscall(machine->ReadRegister(4));
		break;

#endif //network

		case SC_WaitInput:
		DEBUG('a',"Wait input syscall.\n");
		Wait_Input_Syscall();
		break;

		case SC_ReadInput:
		DEBUG('a',"Read input syscall.\n");
		rv=Read_Input_Syscall(machine->ReadRegister(4),machine->ReadRegister(5));
		break;
	
		//Added end
	}

	// Put in the return value and increment the PC
	machine->WriteRegister(2,rv);
	machine->WriteRegister(PrevPCReg,machine->ReadRegister(PCReg));
	machine->WriteRegister(PCReg,machine->ReadRegister(NextPCReg));
	machine->WriteRegister(NextPCReg,machine->ReadRegister(PCReg)+4);
	return;
    }

#ifdef USE_TLB		
	else if ( which == PageFaultException )		//Added in Project3: PageFaultException, used by TLB missing
    {
	//Assumption:
		//If this is called when TLB missing,
		//The missed address should have been saved in BadVAddr Register
		unsigned int VAddr = machine->ReadRegister(BadVAddrReg);
		DEBUG('3',"TLB Miss, Query virtual address is 0x%08x \n", VAddr);
		
		//printf("PageFaultException=%d\n",which);

		if(!OnMissTLB(VAddr))					//If Error occurred during OnTLBMiss, jump to next statement
		{
			printf("FATAL ERROR : TLB update failed, jump to next instruction \n", VAddr);
			machine->WriteRegister(PrevPCReg,machine->ReadRegister(PCReg));
			machine->WriteRegister(PCReg,machine->ReadRegister(NextPCReg));
			machine->WriteRegister(NextPCReg,machine->ReadRegister(PCReg)+4);
			return;
		}
    }
#endif		//USE_TLB
 
	else 
    {
      cout<<"Unexpected user mode exception - which:"<<which<<"  type:"<< type<<endl;
      interrupt->Halt();
    }
}
